#!/usr/bin/env python2

import os
import sys
import socket
import time
import subprocess
import fcntl
import types
import errno
import getopt
import random

from config import Config
from utils import Exp, _dmsg, _dwarn, _derror, _str2dict, _getrack

class Object:
    def __init__(self, storage, name):
        self.name = name
        self.storage = storage
        self.location = storage.location(name, 3)
        self.needmove = False
        
        d = storage.stat(name)
        self.size = int(d['size'])
        self.du = int(d['du'])
        self.repnum = int(d['repnum'])
        self.conn = storage.connection(name, 3)

    def __str__(self):
        location = ""
        for loc in self.location:
            location = location + loc + ","
        return """name:%s,size:%d,du:%d, repnum:%d, location:[%s]""" % (self.name,
                                                                                   self.size,
                                                                                   self.du,
                                                                                   self.repnum,
                                                                                   location)

    def location_clear(self, location):
        done = 0
        for i in range(len(self.location)):
            if (self.location[i] == location):
                self.location[i] = None
                done = 1
                break
        if (done == 0):
            raise Exp(errno.ENOENT, "obj %s, location %s" % (str(self), location))
        self.needmove = True

    def exist(self, location, rack):
        for i in self.location:
            if (i == None):
                continue
            elif (rack):
                if (_getrack(i) == _getrack(location)):
                    return True
            else:
                if (i == location):
                    return True
        return False

    def newlocation(self, location):
        for i in range(len(self.location)):
            if (self.location[i] == None):
                self.location[i] = location
                break

    def move(self, pool):
        if (self.needmove == False):
            return

        used = []
        location = ""
        for loc in self.location:
            location = location + " " + str(loc)
            if (loc):
                used.append(loc)

        _dwarn("move %s[%s] to %s" % (self.name, location, str(pool)))

        a = pool.getlocation(self.repnum - len(used), used)
        for i in a:
            self.newlocation(i)

        self.storage.move_chunk(self.name, self.location)

class Replica:
    def __init__(self, obj):
        self.name = obj.name
        self.du = obj.du / obj.repnum
        self.size = obj.size

        conn = []
        for (k,v) in obj.conn.items():
            conn.append(k)

        if (len(conn) == 1):
            self.moveable = False
        else:
            self.moveable = True

    def __str__(self):
        return "name:%s,du:%s" % (self.name, self.du)

class Node:
    def __init__(self, storage, name):
        self.size = 0
        self.du = 0
        self.name = name
        self.replica = []
        d = storage.nodeinfo(name)
        self.capacity = int(d['capacity'])
    def add(self, obj):
        rep = Replica(obj)
        self.size = self.size + rep.size
        self.du = self.du + rep.du
        self.replica.append(rep)
    def sort(self):
        self.replica = sorted(self.replica, cmp=lambda x,y:cmp(x.du, y.du), reverse=True)

    def __str__(self):
        s = ""
        for i in self.replica:
            s = s + ",(" + str(i) + ")"
        return s

    def pop(self, _du):
        if (_du > self.du):
            return None

        _dmsg("pop from %s" % (self.name))

        self.sort()

        poplist = []
        poplist1 = []
        du = 0
        move = 0
        for i in self.replica:
            if (i.moveable == False):
                continue
            du = du + i.du
            if (du > _du):
                _dmsg("pop %s:%d" % (i.name, i.du))
                move += i.du
                if (move > self.du / 2):
                    break
                poplist.append(i)

        for i in poplist:
            self.du = self.du - i.du
            poplist1.append(i.name)

        return poplist1

class Location:
    def __init__(self, name, capacity):
        self.name = name
        self.capacity = capacity
    def __str__(self):
        return "(name:%s,capacity:%d)" % (self.name, self.capacity)

class Rack:
    def __init__(self, name):
        self.name = name
        self.hosts = []

    def __str__(self):
        loc1 = ''
        for i in self.hosts:
            loc1 = loc1 + i.name + ','
        
        return "(name:%s,hosts:[%s])" % (self.name, loc1)

    def append(self, host):
        self.hosts.append(host)

    def pop(self, name = None):
        if (name == None):
            return self.hosts.pop(0)
        else:
            for i in range(len(self.hosts)):
                if (self.hosts[i] == name):
                    self.hosts.pop(i)
                    break
